package com.xscha.soyue.common.core.utils;

import com.xscha.soyue.common.core.exception.SoyRuntimeException;
import com.xscha.soyue.common.core.exception.status.CommonStatusCode;
import com.xscha.soyue.common.core.exception.status.SoyStatusCode;
import com.xscha.soyue.common.core.mapper.BeanMapperService;
import com.xscha.soyue.common.core.mapper.OrikaBeanMapperService;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Type;
import java.util.Collection;
import java.util.List;
import java.util.Set;

/**
 * 高性能 bean 类型拷贝
 *
 * @author Vondser
 * @version V2024.1.0
 */
@Slf4j
public class BeanMapperUtils {

	private BeanMapperUtils() {
	}

	private volatile static BeanMapperService BEAN_MAPPER_SERVICE;

	static {
		log.info("初始化BeanMapperUtils...");
		OrikaBeanMapperService orikaBeanMapperService = new OrikaBeanMapperService();
		orikaBeanMapperService.setInitialize(true);
		BEAN_MAPPER_SERVICE = orikaBeanMapperService;
	}

	public static void setBeanMapperService(final BeanMapperService beanMapperService) {
		synchronized (BeanMapperUtils.class) {
			if (log.isDebugEnabled()) {
				log.debug("设置BeanMapperUtils中的BeanMapperService...");
			}
			BeanMapperUtils.BEAN_MAPPER_SERVICE = beanMapperService;
		}
	}

	public static BeanMapperService getBeanMapperService() {
		return BeanMapperUtils.BEAN_MAPPER_SERVICE;
	}

	public static <S, T> List<T> mapAsList(Collection<S> source, Class<T> clz) throws SoyRuntimeException {
		try {
			return getBeanMapperService().mapAsList(source, clz);
		}
		catch (Exception e) {
			throw error(source, clz, e);
		}
	}

	public static <S, T> Set<T> mapAsSet(Collection<S> source, Class<T> clz) throws SoyRuntimeException {
		try {
			return getBeanMapperService().mapAsSet(source, clz);
		}
		catch (Exception e) {
			throw error(source, clz, e);
		}
	}

	public static <S, T> T map(S source, Class<T> clz) throws SoyRuntimeException {
		try {
			return getBeanMapperService().map(source, clz, false);
		}
		catch (Exception e) {
			throw error(source, clz, e);
		}
	}

	public static <S, T> T map(S source, Type type) throws SoyRuntimeException {
		try {
			return getBeanMapperService().map(source, type, false);
		}
		catch (Exception e) {
			throw error(source, type.getClass(), e);
		}
	}

	public static <S, T> T map(S source, T target) throws SoyRuntimeException {
		try {
			return getBeanMapperService().map(source, target, false);
		}
		catch (Exception e) {
			throw error(source, target.getClass(), e);
		}
	}

	/**
	 * 如果在Spring扫描情况下，不需要手动执行该方法，该方法使用的情况如下： 在单元测试中，Spring可能不会扫描我们写的转换器
	 * @param converter 转换器
	 */
	public static void registerConverter(Object converter) {
		getBeanMapperService().registerConverter(converter);
	}

	private static <S, T> SoyRuntimeException error(S source, Class<T> target, Throwable cause) {
		String message = String.format(
				((SoyStatusCode) CommonStatusCode.DATA_CONVERT_ERROR).getCode() + "：source--[%s] 转换为 [%s] 失败",
				source.getClass().getName(), target.getName());
		return new SoyRuntimeException(CommonStatusCode.DATA_CONVERT_ERROR, message, cause);
	}

}
